package com.ychen.usercenter.service.impl;

import com.ychen.framework.utils.SnowFlakeUtils;
import com.ychen.usercenter.dao.AccountFlowMapper;
import com.ychen.usercenter.dao.UserInfoMapper;
import com.ychen.usercenter.entity.AccountFlow;
import com.ychen.usercenter.entity.UserInfo;
import com.ychen.usercenter.service.AccountService;
import com.ychen.usercenter.vo.PayForOrderReq;
import com.ychen.usercenter.vo.PayForOrderResp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;

@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private AccountFlowMapper accountFlowMapper;

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public PayForOrderResp payForOrder(PayForOrderReq req) {
        PayForOrderResp resp = new PayForOrderResp();
        // 幂等处理，查询是否已经有流水了
        AccountFlow flow = accountFlowMapper.selectByOrderId(req.getOrderId());
        if (flow != null) {
            resp.setIsSuccess(true);
            return resp;
        }

        UserInfo srcAccount = userInfoMapper.selectByPrimaryKey(req.getSrcAccountId(), true);
        // 余额不足
        if (srcAccount.getBalance().compareTo(req.getTransferAmount()) < 0) {
            resp.setIsSuccess(false);
            resp.setMsg("amount not enough");
            return resp;
        }
        UserInfo targetAccount = userInfoMapper.selectByPrimaryKey(req.getTargetAccountId(), true);

        BigDecimal srcBeforeBalance = srcAccount.getBalance();
        BigDecimal targetBeforeBalance = targetAccount.getBalance();
        //若余额充足，则进行转账动作
        srcAccount.setBalance(srcAccount.getBalance().subtract(req.getTransferAmount()));
        targetAccount.setBalance(targetAccount.getBalance().add(req.getTransferAmount()));

        userInfoMapper.updateByPrimaryKey(srcAccount);
        userInfoMapper.updateByPrimaryKey(targetAccount);

        BigDecimal srcAfterBalance = srcAccount.getBalance();
        BigDecimal targetAfterBalance = targetAccount.getBalance();

        flow = genAccountFlow(req, srcBeforeBalance, targetBeforeBalance, srcAfterBalance, targetAfterBalance);
        accountFlowMapper.insert(flow);
        resp.setIsSuccess(true);
        return resp;
    }

    private AccountFlow genAccountFlow(PayForOrderReq req,
                                       BigDecimal srcBeforeBalance,
                                       BigDecimal targetBeforeBalance,
                                       BigDecimal srcAfterBalance,
                                       BigDecimal targetAfterBalance) {
        AccountFlow flow = new AccountFlow();
        flow.setId(SnowFlakeUtils.nextId());
        flow.setOrderId(req.getOrderId());
        flow.setSrcAccountId(req.getSrcAccountId());
        flow.setTargetAccountId(req.getTargetAccountId());
        flow.setTransferAmount(req.getTransferAmount());
        flow.setTransferTime(new Date());
        flow.setSrcBeforeBalance(srcBeforeBalance);
        flow.setTargetBeforeBalance(targetBeforeBalance);
        flow.setSrcAfterBalance(srcAfterBalance);
        flow.setTargetAfterBalance(targetAfterBalance);
        return flow;
    }
}
